package repodata

import (
	"errors"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type Package struct {
	PkgKey         int    `gorm:"column:pkgKey" json:"pkgKey"`
	PkgId          string `gorm:"column:pkgId" json:"pkgId"`
	Name           string `json:"name"`
	Arch           string `json:"arch"`
	Version        string `json:"version"`
	Epoch          string `json:"epoch"`
	Release        string `json:"release"`
	Summary        string `json:"summary"`
	Description    string `json:"description"`
	Url            string `json:"url"`
	TimeFile       int    `json:"time_file"`
	TimeBuild      int    `json:"time_build"`
	RpmLicense     string `json:"rpm_license"`
	RpmVendor      string `json:"rpm_vendor"`
	RpmGroup       string `json:"rpm_group"`
	RpmBuildhost   string `json:"rpm_buildhost"`
	RpmSourcerpm   string `json:"rpm_sourcerpm"`
	RpmHeaderStart int    `json:"rpm_header_start"`
	RpmHeaderEnd   int    `json:"rpm_header_end"`
	RpmPackager    string `json:"rpm_packager"`
	SizePackage    int    `json:"size_package"`
	SizeInstalled  int    `json:"size_installed"`
	SizeArchive    int    `json:"size_archive"`
	LocationHref   string `json:"location_href"`
	LocationBase   string `json:"location_base"`
	ChecksumType   string `json:"checksum_type"`
}

func (t Package) TableName() string {
	return "packages"
}

type Provide struct {
	Name    string `json:"name"`
	Flags   string `json:"flags"`
	Epoch   string `json:"epoch"`
	Version string `json:"version"`
	Release string `json:"release"`
	PkgKey  int    `gorm:"column:pkgKey" json:"pkgKey"`
}

func (t Provide) TableName() string {
	return "provides"
}

type Require struct {
	Name    string `json:"name"`
	Flags   string `json:"flags"`
	Epoch   string `json:"epoch"`
	Version string `json:"version"`
	Release string `json:"release"`
	PkgKey  int    `gorm:"column:pkgKey" json:"pkgKey"`
	Pre     bool   `json:"pre"`
}

func (t Require) TableName() string {
	return "requires"
}

type File struct {
	Name   string `json:"name"`
	Type   string `json:"type"`
	PkgKey int    `gorm:"column:pkgKey" json:"pkgKey"`
}

func (t File) TableName() string {
	return "files"
}

type Conflict struct {
	Name    string `json:"name"`
	Flags   string `json:"flags"`
	Epoch   string `json:"epoch"`
	Version string `json:"version"`
	Release string `json:"release"`
	PkgKey  int    `gorm:"column:pkgKey" json:"pkgKey"`
}

func (t Conflict) TableName() string {
	return "conflicts"
}

type DBInfo struct {
	Dbversion int    `json:"dbversion"`
	Checksum  string `json:"checksum"`
}

func (t DBInfo) TableName() string {
	return "db_info"
}

type Enhance struct {
	Name    string `json:"name"`
	Flags   string `json:"flags"`
	Epoch   string `json:"epoch"`
	Version string `json:"version"`
	Release string `json:"release"`
	PkgKey  int    `gorm:"column:pkgKey" json:"pkgKey"`
}

func (t Enhance) TableName() string {
	return "enhances"
}

type Obsolete struct {
	Name    string `json:"name"`
	Flags   string `json:"flags"`
	Epoch   string `json:"epoch"`
	Version string `json:"version"`
	Release string `json:"release"`
	PkgKey  int    `gorm:"column:pkgKey" json:"pkgKey"`
}

func (t Obsolete) TableName() string {
	return "obsoletes"
}

type DataPrimary struct {
	Packages []Package
	Requires []Require
	Provides []Provide
}

func GetConnectForSqlite(path2Sqlite string) (db *gorm.DB, err error) {
	return gorm.Open(sqlite.Open(path2Sqlite), &gorm.Config{})
}

func GetPackages(db *gorm.DB) ([]Package, error) {
	var dataList []Package
	err := db.Find(&dataList).Error
	return dataList, err
}

func GetProvides(db *gorm.DB) ([]Provide, error) {
	var dataList []Provide
	err := db.Find(&dataList).Error
	return dataList, err
}

func GetRequires(db *gorm.DB) ([]Require, error) {
	var dataList []Require
	err := db.Find(&dataList).Error
	return dataList, err
}

type PackageWithProvidesAndRequires struct {
	Package
	Requires []Require `gorm:"-"`
	Provides []Provide `gorm:"-"`
}

func GetPackagesWithProvidesAndRequires(db *gorm.DB) ([]PackageWithProvidesAndRequires, error) {
	var dataList []PackageWithProvidesAndRequires
	err := db.Model(&Package{}).Find(&dataList).Error
	provideList, errGetProvides := GetProvides(db)
	requireList, errGetRequires := GetRequires(db)
	mapPkgKey2provideList := map[int][]Provide{}
	mapPkgKey2requireList := map[int][]Require{}
	for _, provide := range provideList {
		mapPkgKey2provideList[provide.PkgKey] = append(mapPkgKey2provideList[provide.PkgKey], provide)
	}
	for _, require := range requireList {
		mapPkgKey2requireList[require.PkgKey] = append(mapPkgKey2requireList[require.PkgKey], require)
	}
	for i, pkg := range dataList {
		dataList[i].Provides = mapPkgKey2provideList[pkg.PkgKey]
		dataList[i].Requires = mapPkgKey2requireList[pkg.PkgKey]
	}
	return dataList, errors.Join(err, errGetProvides, errGetRequires)
}
